8955cb
@@ -15,14 +15,16 @@
package org.springframework.amqp.rabbit.connection;
 
 import java.io.IOException;
 
+import com.rabbitmq.client.Channel;
+
 import org.springframework.amqp.AmqpIOException;
+import org.springframework.transaction.NoTransactionException;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.transaction.support.ResourceHolderSynchronization;
 import org.springframework.transaction.support.TransactionSynchronization;
 import org.springframework.transaction.support.TransactionSynchronizationManager;
 import org.springframework.util.Assert;
 
-import com.rabbitmq.client.Channel;
-
 /**
  * Helper class for managing a Spring based Rabbit {@link org.springframework.amqp.rabbit.connection.ConnectionFactory},
  * in particular for obtaining transactional Rabbit resources for a given ConnectionFactory.
@@ -34,8 +36,10 @@
import com.rabbitmq.client.Channel;
  * @author Mark Fisher
  * @author Dave Syer
  * @author Gary Russell
+ * @author Artem Bilan
  */
 public class ConnectionFactoryUtils {
+
 	/**
 	 * Determine whether the given RabbitMQ Channel is transactional, that is, bound to the current thread by Spring's
 	 * transaction facilities.
@@ -64,15 +68,16 @@
public class ConnectionFactoryUtils {
 	public static RabbitResourceHolder getTransactionalResourceHolder(final ConnectionFactory connectionFactory,
 			final boolean synchedLocalTransactionAllowed) {
 
-		RabbitResourceHolder holder = doGetTransactionalResourceHolder(connectionFactory, new ResourceFactory() {
+		return doGetTransactionalResourceHolder(connectionFactory, new ResourceFactory() {
+
 			@Override
-			public Channel getChannel(RabbitResourceHolder holder) {
-				return holder.getChannel();
+			public Channel getChannel(RabbitResourceHolder holder1) {
+				return holder1.getChannel();
 			}
 
 			@Override
-			public Connection getConnection(RabbitResourceHolder holder) {
-				return holder.getConnection();
+			public Connection getConnection(RabbitResourceHolder holder1) {
+				return holder1.getConnection();
 			}
 
 			@Override
@@ -89,8 +94,8 @@
public class ConnectionFactoryUtils {
 			public boolean isSynchedLocalTransactionAllowed() {
 				return synchedLocalTransactionAllowed;
 			}
+
 		});
-		return holder;
 	}
 
 	/**
@@ -167,8 +172,16 @@
public class ConnectionFactoryUtils {
 		TransactionSynchronizationManager.bindResource(connectionFactory, resourceHolder);
 		resourceHolder.setSynchronizedWithTransaction(true);
 		if (TransactionSynchronizationManager.isSynchronizationActive()) {
+			boolean locallyTransacted = true;
+			try {
+				locallyTransacted = TransactionAspectSupport.currentTransactionStatus().isNewTransaction();
+			}
+			catch (NoTransactionException e) {
+				// Ignore in favor of 'synched' flag before.
+			}
+
 			TransactionSynchronizationManager.registerSynchronization(new RabbitResourceSynchronization(resourceHolder,
-					connectionFactory, synched));
+					connectionFactory, locallyTransacted));
 		}
 	}
 
@@ -226,6 +239,7 @@
public class ConnectionFactoryUtils {
 		 * @return whether to allow for synchronizing a local RabbitMQ transaction
 		 */
 		boolean isSynchedLocalTransactionAllowed();
+
 	}
 
 	/**
@@ -236,19 +250,27 @@
public class ConnectionFactoryUtils {
 	private static class RabbitResourceSynchronization extends
 			ResourceHolderSynchronization<RabbitResourceHolder, Object> {
 
-		private final boolean transacted;
+		private final boolean locallyTransacted;
 
 		private final RabbitResourceHolder resourceHolder;
 
-		public RabbitResourceSynchronization(RabbitResourceHolder resourceHolder, Object resourceKey, boolean transacted) {
+		public RabbitResourceSynchronization(RabbitResourceHolder resourceHolder, Object resourceKey,
+		                                     boolean locallyTransacted) {
 			super(resourceHolder, resourceKey);
 			this.resourceHolder = resourceHolder;
-			this.transacted = transacted;
+			this.locallyTransacted = locallyTransacted;
 		}
 
 		@Override
 		protected boolean shouldReleaseBeforeCompletion() {
-			return !this.transacted;
+			return false;
+		}
+
+		@Override
+		public void afterCommit() {
+			if (this.locallyTransacted) {
+				processResourceAfterCommit(this.resourceHolder);
+			}
 		}
 
 		@Override
@@ -259,10 +281,13 @@
public class ConnectionFactoryUtils {
 		@Override
 		public void afterCompletion(int status) {
 			if (status != TransactionSynchronization.STATUS_COMMITTED) {
-				resourceHolder.rollbackAll();
+				this.resourceHolder.rollbackAll();
 			}
-			if (resourceHolder.isReleaseAfterCompletion()) {
-				resourceHolder.setSynchronizedWithTransaction(false);
+			else if (!this.locallyTransacted) {
+				this.resourceHolder.commitAll();
+			}
+			if (this.resourceHolder.isReleaseAfterCompletion()) {
+				this.resourceHolder.setSynchronizedWithTransaction(false);
 			}
 			super.afterCompletion(status);
 		}
@@ -271,6 +296,7 @@
public class ConnectionFactoryUtils {
 		protected void releaseResource(RabbitResourceHolder resourceHolder, Object resourceKey) {
 			ConnectionFactoryUtils.releaseResources(resourceHolder);
 		}
+
 	}
 
 }
